home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
lin_alg.lha
/
lin_alg
/
matrix1.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-08
|
13KB
|
551 lines
// This may look like C code, but it is really -*- C++ -*-
/*
************************************************************************
*
* Linear Algebra Package
*
* Basic linear algebra operations, level 1
* Element-wise operations
*
************************************************************************
*/
#include "LinAlg.h"
#include <math.h>
#include <builtin.h>
#pragma implementation
/*
*------------------------------------------------------------------------
* Constructors and destructors
*/
void Matrix::allocate(
const short no_rows, // No. of rows
const short no_cols, // No. of cols
const short row_lwb = 1, // Row index lower bound
const short col_lwb = 1 // Col index lower bound
)
{
valid_code = MATRIX_val_code;
assure((nrows=no_rows) > 0, "No. of matrix cols has got to be positive");
assure((ncols=no_cols) > 0, "No. of matrix rows has got to be positive");
Matrix::row_lwb = row_lwb;
Matrix::col_lwb = col_lwb;
name = "";
nelems = nrows * ncols;
assert( (index = calloc(ncols,sizeof(REAL *))) != 0 );
assert( (elements = calloc(nelems,sizeof(REAL))) != 0 );
register int i;
for(i=0; i<ncols; i++)
index[i] = &elements[i*nrows];
}
Matrix::~Matrix(void) // Dispose the Matrix struct
{
is_valid();
delete index;
delete elements;
if( name[0] != '\0' )
delete name;
valid_code = 0;
}
// Set a new Matrix name
void Matrix::set_name(const char * new_name)
{
if( name[0] != '\0' )
delete name; // delete the old name (if any)
name = strcpy(calloc(strlen(new_name)+1,sizeof(char)),new_name);
}
// Erase the old matrix and create a
// new one according to new boundaries
// with indexation starting at 1
void Matrix::resize_to(const short nrows, const short ncols)
{
is_valid();
if( nrows == Matrix::nrows && ncols == Matrix::ncols )
return;
delete index;
delete elements;
char * old_name = name;
allocate(nrows,ncols);
name = old_name;
}
// Erase the old matrix and create a
// new one according to new boundaries
void Matrix::resize_to(const short row_lwb, const short row_upb,
const short col_lwb, const short col_upb)
{
is_valid();
const int new_nrows = row_upb-row_lwb+1;
const int new_ncols = col_upb-col_lwb+1;
Matrix::row_lwb = row_lwb;
Matrix::col_lwb = col_lwb;
if( new_nrows == Matrix::nrows && new_ncols == Matrix::ncols )
return;
delete index;
delete elements;
char * old_name = name;
allocate(new_nrows,new_ncols,row_lwb,col_lwb);
name = old_name;
}
/*
*------------------------------------------------------------------------
* Making a matrix of a special kind
*/
// Make a unit matrix
// (Matrix needn't be a square one)
Matrix& Matrix::unit_matrix(void)
{
is_valid();
register REAL *ep = elements;
register int i,j;
for(i=0; i < nrows; i++)
for(j=0; j < ncols; j++)
*ep++ = ( i==j ? 1.0 : 0.0 );
return *this;
}
// Make a Hilbert matrix
// Hilb[i,j] = 1/(i+j-1), i,j=1...max, OR
// Hilb[i,j] = 1/(i+j+1), i,j=0...max-1
// (Matrix needn't be a square one)
Matrix& Matrix::hilbert_matrix(void)
{
is_valid();
register REAL *ep = elements;
register int i,j;
for(i=0; i < nrows; i++)
for(j=0; j < ncols; j++)
*ep++ = 1./(i+j+1);
return *this;
}
/*
*------------------------------------------------------------------------
* Matrix-scalar arithmetics
*/
// Assign a value to all the elements
Matrix& Matrix::operator = (const double val)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
*ep++ = val;
return *this;
}
// Add to all the elements
Matrix& Matrix::operator += (const double val)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
*ep++ += val;
return *this;
}
// Subtract a value from all the elements
Matrix& Matrix::operator -= (const double val)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
*ep++ -= val;
return *this;
}
// Multiply all the elements by a given value
Matrix& Matrix::operator *= (const double val)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
*ep++ *= val;
return *this;
}
// Return TRUE if all the elements are equal
// to a given value
int Matrix::operator == (const double val) const
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
if( *ep++ != val )
return 0;
return 1;
}
// Return TRUE if all the elements are stricly
// less than a given value
int Matrix::operator < (const double val) const
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
if( !(*ep++ < val) )
return 0;
return 1;
}
// Return TRUE if all the elements are stricly
// greater than a given value
int Matrix::operator > (const double val) const
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems;)
if( !(*ep++ > val) )
return 0;
return 1;
}
/*
*------------------------------------------------------------------------
* Apply algebraic functions to all the matrix elements
*/
// Take an absolute value of a matrix
Matrix& Matrix::abs(void)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems; ep++)
*ep = ::abs(*ep);
return *this;
}
// Square each element
Matrix& Matrix::sqr(void)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems; ep++)
*ep = *ep * *ep;
return *this;
}
// Take a square root of all the elements
Matrix& Matrix::sqrt(void)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems; ep++)
if( *ep >= 0 )
*ep = ::sqrt(*ep);
else
info(),
_error("(%d,%d)-th element, %g, is negative. Can't take the square root",
(ep-elements) % nrows + row_lwb,
(ep-elements) / nrows + col_lwb, *ep );
return *this;
}
// Apply a user defined function
Matrix& Matrix::user_function(USER_DEFINED_REAL_F uf)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems; ep++)
*ep = (*uf)(*ep);
return *this;
}
Matrix& Matrix::user_function(USER_DEFINED_DOUBLE_F uf)
{
is_valid();
register REAL * ep;
for(ep=elements; ep < elements+nelems; ep++)
*ep = (*uf)(*ep);
return *this;
}
/*
*------------------------------------------------------------------------
* Matrix-Matrix element-wise operations
*/
// Check to see if two matrices are identical
int operator == (const Matrix& im1, const Matrix& im2)
{
are_compatible(im1,im2);
return (memcmp(im1.elements,im2.elements,im1.nelems*sizeof(REAL)) == 0);
}
// Add the source to the target
Matrix& operator += (Matrix& target, const Matrix& source)
{
are_compatible(target,source);
register REAL * sp = source.elements;
register REAL * tp = target.elements;
for(; tp < target.elements+target.nelems;)
*tp++ += *sp++;
return target;
}
// Subtract the source from the target
Matrix& operator -= (Matrix& target, const Matrix& source)
{
are_compatible(target,source);
register REAL * sp = source.elements;
register REAL * tp = target.elements;
for(; tp < target.elements+target.nelems;)
*tp++ -= *sp++;
return target;
}
// Modified addition
// Target += scalar*Source
Matrix& add(Matrix& target, const double scalar,const Matrix& source)
{
are_compatible(target,source);
register REAL * sp = source.elements;
register REAL * tp = target.elements;
for(; tp < target.elements+target.nelems;)
*tp++ += scalar * *sp++;
return target;
}
// Multiply target by the source
// element-by-element
Matrix& element_mult(Matrix& target, const Matrix& source)
{
are_compatible(target,source);
register REAL * sp = source.elements;
register REAL * tp = target.elements;
for(; tp < target.elements+target.nelems;)
*tp++ *= *sp++;
return target;
}
// Divide target by the source
// element-by-element
Matrix& element_div(Matrix& target, const Matrix& source)
{
are_compatible(target,source);
register REAL * sp = source.elements;
register REAL * tp = target.elements;
for(; tp < target.elements+target.nelems;)
*tp++ /= *sp++;
return target;
}
/*
*------------------------------------------------------------------------
* Compute matrix norms
*/
// Row matrix norm
// MAX{ SUM{ |M(i,j)|, over j}, over i}
// The norm is induced by the infinity
// vector norm
double Matrix::row_norm(void) const
{
is_valid();
register REAL * ep = elements;
register double norm = 0;
while(ep < elements+nrows) // Scan the matrix row-after-row
{
register int j;
register double sum = 0;
for(j=0; j<ncols; j++,ep+=nrows) // Scan a row to compute the sum
sum += ::abs(*ep);
ep -= nelems - 1; // Point ep to the beg of the next row
norm = ::max(norm,sum);
}
assert( ep == elements + nrows );
return norm;
}
// Column matrix norm
// MAX{ SUM{ |M(i,j)|, over i}, over j}
// The norm is induced by the 1.
// vector norm
double Matrix::col_norm(void) const
{
is_valid();
register REAL * ep = elements;
register double norm = 0;
while(ep < elements+nelems) // Scan the matrix col-after-col
{ // (i.e. in the natural order of elems)
register int i;
register double sum = 0;
for(i=0; i<nrows; i++) // Scan a col to compute the sum
sum += ::abs(*ep++);
norm = ::max(norm,sum);
}
assert( ep == elements + nelems );
return norm;
}
// Square of the Euclidian norm
// SUM{ m(i,j)^2 }
double Matrix::e2_norm(void) const
{
is_valid();
register REAL * ep;
register double sum = 0;
for(ep=elements; ep < elements+nelems;)
sum += ::sqr(*ep++);
return sum;
}
// Square of the Euclidian norm of the
// difference between two matrices
double e2_norm(const Matrix& m1, const Matrix& m2)
{
are_compatible(m1,m2);
register REAL * mp1 = m1.elements;
register REAL * mp2 = m2.elements;
register double sum = 0;
for(; mp1 < m1.elements+m1.nelems;)
sum += sqr(*mp1++ - *mp2++);
return sum;
}
/*
*------------------------------------------------------------------------
* Some service operations
*/
void Matrix::info(void) const // Print some information about the matrix
{
is_valid();
message("\nMatrix %d:%dx%d:%d '%s'",row_lwb,nrows+row_lwb-1,
col_lwb,ncols+col_lwb-1,name);
}
// Print the Matrix as a table of elements
// (zeros are printed as dots)
void Matrix::print(const char * title) const
{
is_valid();
message("\nMatrix %dx%d '%s' is as follows",nrows,ncols,title);
const int cols_per_sheet = 6;
register int sheet_counter;
for(sheet_counter=1; sheet_counter<=ncols; sheet_counter +=cols_per_sheet)
{
message("\n\n |");
register int i,j;
for(j=sheet_counter; j<sheet_counter+cols_per_sheet && j<=ncols; j++)
message(" %6d |",j+col_lwb-1);
message("\n%s\n",_Minuses);
for(i=1; i<=nrows; i++)
{
message("%4d |",i+row_lwb-1);
for(j=sheet_counter; j<sheet_counter+cols_per_sheet && j<=ncols; j++)
message("%11.4g ",(*this)(i+row_lwb-1,j+col_lwb-1));
message("\n");
}
}
message("Done\n");
}
#include <builtin.h>
void compare( // Compare the two Matrixs
const Matrix& matrix1, // and print out the result of comparison
const Matrix& matrix2,
const char * title )
{
register int i,j;
are_compatible(matrix1,matrix2);
message("\n\nComparison of two Matrices:\n\t%s",title);
matrix1.info();
matrix2.info();
double norm1 = 0, norm2 = 0; // Norm of the Matrixs
double ndiff = 0; // Norm of the difference
int imax=0,jmax=0; // For the elements that differ most
REAL difmax = -1;
register REAL *mp1 = matrix1.elements; // Matrix element pointers
register REAL *mp2 = matrix2.elements;
for(j=0; j < matrix1.ncols; j++) // Due to the column-wise arrangement,
for(i=0; i < matrix1.nrows; i++) // the row index changes first
{
REAL mv1 = *mp1++;
REAL mv2 = *mp2++;
REAL diff = abs(mv1-mv2);
if( diff > difmax )
{
difmax = diff;
imax = i;
jmax = j;
}
norm1 += abs(mv1);
norm2 += abs(mv2);
ndiff += abs(diff);
}
imax += matrix1.row_lwb, jmax += matrix1.col_lwb;
message("\nMaximal discrepancy \t\t%g",difmax);
message("\n occured at the point\t\t(%d,%d)",imax,jmax);
const REAL mv1 = matrix1(imax,jmax);
const REAL mv2 = matrix2(imax,jmax);
message("\n Matrix 1 element is \t\t%g",mv1);
message("\n Matrix 2 element is \t\t%g",mv2);
message("\n Absolute error v2[i]-v1[i]\t\t%g",mv2-mv1);
message("\n Relative error\t\t\t\t%g\n",
(mv2-mv1)/max(abs(mv2+mv1)/2,1e-7) );
message("\n||Matrix 1|| \t\t\t%g",norm1);
message("\n||Matrix 2|| \t\t\t%g",norm2);
message("\n||Matrix1-Matrix2||\t\t\t\t%g",ndiff);
message("\n||Matrix1-Matrix2||/sqrt(||Matrix1|| ||Matrix2||)\t%g\n\n",
ndiff/max( sqrt(norm1*norm2), 1e-7 ) );
}